﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Assist;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Revit;
using YJKArchMethodLibrary.Utils;
using YJKCodeBase.WinForm;
using YJKView;
using Transfer.CommonUnit;

namespace ColumnModuleAndEdit.ColumnModule
{
	[Regeneration(RegenerationOption.Manual)]
	[Transaction(TransactionMode.Manual)]
	internal class CmdColumnBreakWall : IExternalCommand
	{
		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result Execute(ExternalCommandData cmdData, ref string message, ElementSet elements)
		{
			CmdViewType types = (CmdViewType)127;
			if (SwitchView.SetUsableView(types, cmdData) != Autodesk.Revit.UI.Result.Succeeded)
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			this.m_cmdData = cmdData;
			this.m_doc = cmdData.Application.ActiveUIDocument.Document;
			this.m_selection = cmdData.Application.ActiveUIDocument.Selection;
			RevitVersionFuncs.ClearSelection(this.m_selection);
			if (CmdColumnBreakWall._hWndRevit == null)
			{
				Process currentProcess = Process.GetCurrentProcess();
				IntPtr mainWindowHandle = currentProcess.MainWindowHandle;
				CmdColumnBreakWall._hWndRevit = new WindowHandle(mainWindowHandle);
			}
			ColumnBreakWallForm columnBreakWallForm = new ColumnBreakWallForm(cmdData);
			columnBreakWallForm.Show(CmdColumnBreakWall._hWndRevit);
			int wMsg = 7;
			CmdColumnBreakWall.SendMessage(CmdColumnBreakWall._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			Transaction transaction = new Transaction(this.m_doc, "ColumnBreakWall");
			Result result;
			for (;;)
			{
				transaction.Start();
				ColumnFilter columnFilter = new ColumnFilter();
				IList<Element> list = null;
				try
				{
					list = this.m_selection.PickElementsByRectangle(columnFilter, "请框选柱子");
				}
				catch (Autodesk.Revit.Exceptions.OperationCanceledException)
				{
					transaction.RollBack();
					columnBreakWallForm.Close();
					result = Autodesk.Revit.UI.Result.Succeeded;
					break;
				}
				catch (Exception)
				{
					transaction.RollBack();
					columnBreakWallForm.Close();
					result = Autodesk.Revit.UI.Result.Failed;
					break;
				}
				bool breakState = columnBreakWallForm.GetBreakState();
				try
				{
					foreach (Element column in list)
					{
						if (breakState)
						{
							this.ColumnBreakWall(column);
						}
						else
						{
							this.ColumnNotBreakWall(column);
						}
					}
				}
				catch (Exception)
				{
					transaction.RollBack();
					columnBreakWallForm.Close();
					result = Autodesk.Revit.UI.Result.Failed;
					break;
				}
				transaction.Commit();
			}
			return result;
		}

		private void ColumnBreakWall(Element column)
		{
			List<Element> wallsJoinedElement = this.GetWallsJoinedElement(column);
			List<Element> wallsIntersectElement = this.GetWallsIntersectElement(column);
			List<Element> list = new List<Element>();
			list.AddRange(wallsJoinedElement);
			list.AddRange(wallsIntersectElement);
			List<XYZ> list2 = new List<XYZ>();
			ColumnProfileExtractor columnProfileExtractor = new ColumnProfileExtractor(this.m_cmdData.Application);
			FamilyInstance column2 = column as FamilyInstance;
			List<EdgeInfo> columnProfile = columnProfileExtractor.GetColumnProfile(column2);
			foreach (EdgeInfo edgeInfo in columnProfile)
			{
				Curve curve = edgeInfo.ConvertTo(this.m_cmdData.Application.Application);
				list2.AddRange(curve.Tessellate());
			}
			AssistFunc.CompressArray(list2);
			foreach (Element element in list)
			{
				LocationCurve locationCurve = element.Location as LocationCurve;
				Curve curve2 = locationCurve.Curve;
				XYZ endPoint = curve2.GetEndPoint(0);
				XYZ endPoint2 = curve2.GetEndPoint(1);
				if (Geometry.PointInPloygon(list2, endPoint, 0.0001, 0.0001) != -1 || Geometry.PointInPloygon(list2, endPoint2, 0.0001, 0.0001) != -1)
				{
					this.JoinTwoElements(column, element);
				}
				else
				{
					this.ColumnBreakWall(column, element);
				}
			}
		}

		private void ColumnNotBreakWall(Element column)
		{
			List<Element> wallsJoinedElement = this.GetWallsJoinedElement(column);
			foreach (Element wall in wallsJoinedElement)
			{
				this.SetJoinOrder(column, wall);
			}
			List<Element> wallsIntersectElement = this.GetWallsIntersectElement(column);
			foreach (Element wall2 in wallsIntersectElement)
			{
				this.JoinTwoElements(column, wall2);
			}
		}

		private List<Element> GetWallsJoinedElement(Element column)
		{
			List<Element> list = new List<Element>();
			ICollection<ElementId> joinedElements = JoinGeometryUtils.GetJoinedElements(this.m_doc, column);
			foreach (ElementId elementId in joinedElements)
			{
				Element element = this.m_doc.GetElement(elementId);
				Wall wall = element as Wall;
				if (wall != null)
				{
					list.Add(wall);
				}
			}
			return list;
		}

		private List<Element> GetWallsIntersectElement(Element column)
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_doc);
			filteredElementCollector.OfClass(typeof(Wall));
			ElementIntersectsElementFilter elementIntersectsElementFilter = new ElementIntersectsElementFilter(column);
			filteredElementCollector.WherePasses(elementIntersectsElementFilter);
			List<Element> list = new List<Element>();
			foreach (Element item in filteredElementCollector)
			{
				list.Add(item);
			}
			return list;
		}

		private void SetJoinOrder(Element column, Element wall)
		{
			if (!JoinGeometryUtils.IsCuttingElementInJoin(this.m_doc, column, wall))
			{
				JoinGeometryUtils.SwitchJoinOrder(this.m_doc, column, wall);
			}
		}

		private void JoinTwoElements(Element column, Element wall)
		{
			if (!JoinGeometryUtils.AreElementsJoined(this.m_doc, column, wall))
			{
				JoinGeometryUtils.JoinGeometry(this.m_doc, column, wall);
			}
			this.SetJoinOrder(column, wall);
		}

		private void UnJoinTwoElements(Element column, Element wall)
		{
			if (JoinGeometryUtils.AreElementsJoined(this.m_doc, column, wall))
			{
				JoinGeometryUtils.UnjoinGeometry(this.m_doc, column, wall);
			}
		}

		private void UnJoinWalls(Wall wall)
		{
			if (WallUtils.IsWallJoinAllowedAtEnd(wall, 0))
			{
				WallUtils.DisallowWallJoinAtEnd(wall, 0);
			}
			if (WallUtils.IsWallJoinAllowedAtEnd(wall, 1))
			{
				WallUtils.DisallowWallJoinAtEnd(wall, 1);
			}
		}

		private void ColumnBreakWall(Element column, Element wall)
		{
			ICollection<ElementId> joinedElements = JoinGeometryUtils.GetJoinedElements(this.m_doc, wall);
			LocationCurve locationCurve = wall.Location as LocationCurve;
			Curve curve = locationCurve.Curve;
			XYZ endPoint = curve.GetEndPoint(0);
			XYZ endPoint2 = curve.GetEndPoint(1);
			LocationPoint locationPoint = column.Location as LocationPoint;
			XYZ point = locationPoint.Point;
			XYZ breakPoint = this.GetBreakPoint(point, wall);
			int elementCount = MirrorOperater.GetElementCount(this.m_doc);
			ICollection<ElementId> source = ElementTransformUtils.CopyElement(this.m_doc, wall.Id, XYZ.Zero);
			ICollection<ElementId> source2 = ElementTransformUtils.CopyElement(this.m_doc, wall.Id, XYZ.Zero);
			Wall wall2 = this.m_doc.GetElement(source.ElementAt(0)) as Wall;
			Wall wall3 = this.m_doc.GetElement(source2.ElementAt(0)) as Wall;
			LocationCurve locationCurve2 = wall2.Location as LocationCurve;
			LocationCurve locationCurve3 = wall3.Location as LocationCurve;
			List<ElementId> elementsIdAfter = MirrorOperater.GetElementsIdAfter(elementCount, this.m_doc);
			this.m_doc.Delete(wall.Id);
			this.UnJoinWalls(wall2);
			this.UnJoinWalls(wall3);
			this.RemoveElementsExceedWall(endPoint, breakPoint, wall2, elementsIdAfter);
			this.RemoveElementsExceedWall(breakPoint, endPoint2, wall3, elementsIdAfter);
			try
			{
				Line line = locationCurve2.Curve as Line;
				if (null != line)
				{
					locationCurve2.Curve = Line.CreateBound(endPoint, breakPoint);
					locationCurve3.Curve = Line.CreateBound(breakPoint, endPoint2);
				}
				Arc arc = locationCurve2.Curve as Arc;
				if (null != arc)
				{
					XYZ xyz = AxisAssistFunc.CalculatMidPoint(endPoint, breakPoint, arc.Center, arc.Normal);
					locationCurve2.Curve = Arc.Create(endPoint, breakPoint, xyz);
					xyz = AxisAssistFunc.CalculatMidPoint(breakPoint, endPoint2, arc.Center, arc.Normal);
					locationCurve3.Curve = Arc.Create(breakPoint, endPoint2, xyz);
				}
				this.JoinTwoElements(column, wall2);
				this.JoinTwoElements(column, wall3);
				WallUtils.AllowWallJoinAtEnd(wall2, 0);
				WallUtils.AllowWallJoinAtEnd(wall3, 1);
				this.m_doc.Regenerate();
				foreach (ElementId elementId in joinedElements)
				{
					Element element = this.m_doc.GetElement(elementId);
					FamilyInstance familyInstance = element as FamilyInstance;
					if (familyInstance != null)
					{
						int integerValue = familyInstance.Category.Id.IntegerValue;
						if (-2001330 == integerValue || -2000100 == integerValue)
						{
							if (YJKRevitTools.IsElementIntersectsElement(element, wall2))
							{
								JoinGeometryUtils.JoinGeometry(this.m_doc, element, wall2);
								this.SetJoinOrder(element, wall2);
							}
							if (YJKRevitTools.IsElementIntersectsElement(element, wall3))
							{
								JoinGeometryUtils.JoinGeometry(this.m_doc, element, wall3);
								this.SetJoinOrder(element, wall3);
							}
						}
					}
				}
				this.m_doc.Regenerate();
			}
			catch (Exception ex)
			{
				string message = ex.Message;
			}
		}

		private List<Element> GetAssociateElementByWall(Wall wall, List<Element> elements)
		{
			List<Element> list = new List<Element>();
			foreach (Element element in elements)
			{
				FamilyInstance familyInstance = element as FamilyInstance;
				if (familyInstance != null && familyInstance.Host != null && familyInstance.Host.Id == wall.Id)
				{
					list.Add(familyInstance);
				}
				Opening opening = element as Opening;
				if (opening != null && opening.Host != null && opening.Host.Id == wall.Id)
				{
					list.Add(opening);
				}
			}
			return list;
		}

		private void RemoveElementsExceedWall(XYZ ptStart, XYZ ptEnd, Wall wall, List<ElementId> eleIds)
		{
			List<Element> list = new List<Element>();
			foreach (ElementId elementId in eleIds)
			{
				Element element = this.m_doc.GetElement(elementId);
				list.Add(element);
			}
			List<Element> associateElementByWall = this.GetAssociateElementByWall(wall, list);
			LocationCurve locationCurve = wall.Location as LocationCurve;
			Curve curve = locationCurve.Curve;
			Curve curve2 = null;
			Line line = curve as Line;
			if (null != line)
			{
				curve2 = Line.CreateBound(ptStart, ptEnd);
			}
			Arc arc = curve as Arc;
			if (null != arc)
			{
				XYZ xyz = AxisAssistFunc.CalculatMidPoint(ptStart, ptEnd, arc.Center, arc.Normal);
				curve2 = Arc.Create(ptStart, ptEnd, xyz);
			}
			foreach (Element element2 in associateElementByWall)
			{
				FamilyInstance familyInstance = element2 as FamilyInstance;
				if (familyInstance != null)
				{
					LocationPoint locationPoint = familyInstance.Location as LocationPoint;
					if (locationPoint != null)
					{
						XYZ point = locationPoint.Point;
						ConnectHelper connectHelper = new ConnectHelper();
						if (connectHelper.Project(point, curve2, 0.0001) == null)
						{
							this.m_doc.Delete(familyInstance.Id);
						}
					}
				}
				Opening opening = element2 as Opening;
				if (opening != null)
				{
					IList<XYZ> boundaryRect = opening.BoundaryRect;
					if (2 == boundaryRect.Count)
					{
						XYZ xyz2 = boundaryRect[1] - boundaryRect[0];
						XYZ point2 = boundaryRect[0] + xyz2 / 2.0;
						ConnectHelper connectHelper2 = new ConnectHelper();
						if (connectHelper2.Project(point2, curve2, 0.0001) == null)
						{
							this.m_doc.Delete(opening.Id);
						}
					}
				}
			}
		}

		private XYZ GetBreakPoint(XYZ ptColumn, Element wall)
		{
			LocationCurve locationCurve = wall.Location as LocationCurve;
			Curve curve = locationCurve.Curve;
			return curve.Project(ptColumn).XYZPoint;
		}

		private ExternalCommandData m_cmdData;

		private Document m_doc;

		private Selection m_selection;

		public static WindowHandle _hWndRevit;
	}
}
